package com.xjx.common.util;

import lombok.extern.slf4j.Slf4j;
import java.util.*;

@Slf4j
public class ConsistentHashUtil {
    
    /**
     * 虚拟节点数量，建议为实际节点数的100-200倍
     */
    private static final int VIRTUAL_NODES = 150;
    
    /**
     * 一致性哈希环
     */
    private static final TreeMap<Long, String> hashRing = new TreeMap<>();
    
    /**
     * 初始化一致性哈希环
     * @param nodes 实际节点列表
     */
    public static void initHashRing(List<String> nodes) {
        hashRing.clear();
        for (String node : nodes) {
            addNode(node);
        }
        log.info("一致性哈希环初始化完成，节点数量: {}, 虚拟节点数量: {}", nodes.size(), hashRing.size());
    }
    
    /**
     * 添加节点到哈希环
     * @param node 节点名称
     */
    public static void addNode(String node) {
        for (int i = 0; i < VIRTUAL_NODES; i++) {
            String virtualNode = node + "#" + i;
            long hash = hash(virtualNode);
            hashRing.put(hash, node);
        }
        log.info("添加节点: {} 到哈希环，虚拟节点数量: {}", node, VIRTUAL_NODES);
    }
    
    /**
     * 从哈希环移除节点
     * @param node 节点名称
     */
    public static void removeNode(String node) {
        Iterator<Map.Entry<Long, String>> iterator = hashRing.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Long, String> entry = iterator.next();
            if (entry.getValue().equals(node)) {
                iterator.remove();
            }
        }
        log.info("从哈希环移除节点: {}", node);
    }
    
    /**
     * 根据key获取对应的节点
     * @param key 分片键
     * @return 节点名称
     */
    public static String getNode(String key) {
        if (hashRing.isEmpty()) {
            throw new RuntimeException("哈希环未初始化");
        }
        
        long hash = hash(key);
        Map.Entry<Long, String> entry = hashRing.ceilingEntry(hash);
        
        // 如果没有找到大于等于hash的节点，则使用第一个节点（环形结构）
        if (entry == null) {
            entry = hashRing.firstEntry();
        }
        
        return entry.getValue();
    }
    
    /**
     * 根据key获取对应的节点（支持数字类型）
     * @param key 分片键
     * @return 节点名称
     */
    public static String getNode(Long key) {
        return getNode(String.valueOf(key));
    }
    
    /**
     * 计算哈希值
     * @param key 键
     * @return 哈希值
     */
    private static long hash(String key) {
        return Math.abs(key.hashCode());
    }
    
    /**
     * 获取所有节点
     * @return 节点集合
     */
    public static Set<String> getAllNodes() {
        return new HashSet<>(hashRing.values());
    }
    
    /**
     * 获取哈希环信息
     * @return 哈希环信息
     */
    public static Map<String, Integer> getHashRingInfo() {
        Map<String, Integer> nodeCount = new HashMap<>();
        for (String node : hashRing.values()) {
            nodeCount.put(node, nodeCount.getOrDefault(node, 0) + 1);
        }
        return nodeCount;
    }
}

